#pragma once

#include "fxcc/core/pch.h"

#include "glm/glm.hpp"
#include "imgui.h"

#include "sysx/System.h"
#include "mustache.hpp"

namespace fxcc
{
	struct FXCC_API Base
	{
		int m_ImguiFlag{ 0 };

		bool m_Selected{ 0 };

		bool m_Exist{ true };

		bool m_Available{ true };

		float m_ScrollY{ 0.f };

		bool m_HasTreeNodedRender{ false };

		bool m_TreeNode{ false };

		std::string m_UUID;

		int m_NodeId;

		glm::vec2 m_NodePos{ 100,100 };

		bool m_FirstRender{ true };

		Base()
		{
			m_UUID = genUUID();
			m_NodeId = generateIDFromTime();

			//m_ImguiFlag = (m_ImguiFlag == 0) ? std::numeric_limits<int>::max() : -m_ImguiFlag;
		}
		static int generateIDFromTime() {
			auto now = std::chrono::system_clock::now();

			auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
			std::hash<long long> hasher;
			return static_cast<int>(hasher(timestamp));  
		}
		static bool UUIDsContain(const std::vector<std::string>& uuids, std::string id)
		{
			for (const auto& uuid : uuids)
			{
				if (uuid == id)
				{
					return true;
				}
			}
			return false;
		}
		static bool CreateParentDirs(const std::string& path)
		{
			fs::path _p(path);
			bool hasParentPath = _p.has_parent_path();
			
			if (hasParentPath) {
				if (!fs::exists(_p.parent_path()))
				{
					fs::create_directories(_p.parent_path());
				}
			}
			return true;
		}
		static bool StringsContain(const std::vector<std::string>& uuids, std::string id)
		{
			for (const auto& uuid : uuids)
			{
				if (uuid == id)
				{
					return true;
				}
			}
			return false;
		}


		static std::string genUUID()
		{
			std::random_device rd;
			std::mt19937_64 gen(rd());
			std::uniform_int_distribution<uint32_t> dist(0, 0xFFFFFFFF);

			uint32_t part1 = dist(gen);
			uint16_t part2 = dist(gen) & 0xFFFF;
			uint16_t part3 = (dist(gen) & 0x0FFF) | 0x4000;
			uint16_t part4 = (dist(gen) & 0x3FFF) | 0x8000;
			uint32_t part5 = dist(gen);
			uint32_t part6 = dist(gen);

			std::ostringstream oss;
			oss << std::hex << std::setfill('0') << std::setw(8) << part1 << "-"
				<< std::setw(4) << part2 << "-"
				<< std::setw(4) << part3 << "-"
				<< std::setw(4) << part4 << "-"
				<< std::setw(8) << part5 << std::setw(4) << (part6 >> 16);
			return oss.str();

		};
		static std::vector<std::string> GetAllFiles(const std::string& dir, const std::string& suffix)
		{
			std::vector<std::string> res;
			ProcessAllFilesSuffix(res, dir, suffix);
			return res;
		}
		static std::vector<std::string> GetAllDirs(const std::string& dir)
		{
			std::vector<std::string> res;
			ProcessAllDirs(res, dir);
			return res;
		}
		static void ProcessAllDirs(std::vector<std::string>& target, const std::string& dir)
		{
			if (!fs::exists(dir))
			{
				return ;
			}
			if (!fs::is_directory(dir))
			{
				return;
			}

			target.push_back(dir);
			for (const auto& it : fs::directory_iterator(dir))
			{
				auto _p = it.path();
				if (fs::is_directory(_p))
				{
					target.push_back(_p.string());
				}
			}
		}
		static void ProcessAllFilesSuffix(std::vector<std::string>& target, const std::string& dir, const std::string& suffix)
		{
			if (!fs::exists(dir)) {

				return;
			}
			if (!fs::is_directory(dir))
			{
				return;
			}
			for (const auto& it : fs::directory_iterator(dir))
			{
				std::string fileName = it.path().filename().string();

				if (!fs::is_directory(it))
				{
					if (GetSuffix(fileName) == suffix)
					{
						target.push_back(it.path().string());
					}
				}
			}
		}

		static std::string GetNoSuffixName(const std::string& filename)
		{
			size_t pos = filename.find_last_of('.');
			if (pos == std::string::npos)
			{
				return filename; 
			}
			return filename.substr(0, pos);
		}
		static std::string GetSuffix(const std::string &filename)
		{
			size_t pos = filename.find_last_of('.');
			if (pos == std::string::npos || pos == filename.length() - 1)
			{
				return std::string();
			}
			return filename.substr(pos);
		};

		static std::string normalizePath(const std::string &path)
		{
			std::string normalized = path;
			std::replace(normalized.begin(), normalized.end(), '\\', '/');
			auto normalized_p = fs::relative(normalized, "./");
			return normalized_p.string();
		};
		
		void setFlagBit(const int index, bool value)
		{
			if (value)
			{
				m_ImguiFlag|= (1 << index); 
			}
			else
			{
				m_ImguiFlag &= ~(1 << index); 
			}
		}

		bool getFlagBit(const int index)
		{
			return (m_ImguiFlag & (1 << index)) != 0;
		}
	public:

		ImVec2 m_StartPos{};

		ImVec2 m_EndPos{};


	};
	


}